/**
 * Various utility methods to handle Icelandic PIDs (kennitala).
 *
 * In this class, the PID is referred to as a "persidno", that's lingo inherited
 * from our previous computer systems.
 *
 * http://www.thjodskra.is/en/id-numbers/
 * http://en.wikipedia.org/wiki/Kennitala
 *
 * @author Hugi Thordarson
 * @converted to C# Ingi Gauti Ragnarsson
 */
using System;
using System.Text.RegularExpressions;

namespace Is.Net {
	public class PersidnoUtilities {

			private static readonly String DEFAULT_PERSIDNO_DELIMITER = "-";

			/**
			 * Returns true if the persidno is an individual
			 *
			 * @param persidno The persidno to check.
			 */
			public static bool IsIndividualPersidno( String persidno ) {

					if( persidno == null ) {
							return false;
					}

					persidno = CleanupPersidno( persidno );
					int marker = int.Parse( persidno.Substring( 0, 1 ) );
					return marker < 4;
			}

			/**
			 * Returns true if the persidno is for a company.
			 *
			 * @param persidno The persidno to check.
			 */
			public static bool IsCompanyPersidno( String persidno ) {

					if( persidno == null ) {
							return false;
					}

					persidno = CleanupPersidno( persidno );
					int marker = int.Parse( persidno.Substring( 0, 1 ) );
					return marker == 4 || marker == 5 || marker == 6 || marker == 7;
			}

			/**
			 * Gets the birthdate of the given individual.
			 *
			 * @param persidno The persidno to check.
			 * @return the birthdate of the individual.
			 */
			public static DateTime BirthdateFromPersidno( String persidno ) {

					if( persidno == null ) {
							return DateTime.MinValue;
					}

					persidno = CleanupPersidno( persidno );

					int day = BirthDayFromPersidno( persidno );
					int month = BirthMonthFromPersidno( persidno );
					int fullYear = BirthyearFromPersidno( persidno );

					DateTime dt = new DateTime(fullYear, month, day);
					return dt;
			}

			/**
			 * Derives a person's age from a persidno.
			 *
			 * @param persidno The persidno to check.
			 */
			public static int AgeFromPersidno( String persidno ) {

					if( persidno == null ) {
							return 0;
					}

					DateTime birthDate = BirthdateFromPersidno( persidno );
					return DateTime.Now.Year - birthDate.Year;
			}

			/**
			 * Validates a persidno's structure to see if it complies with the validation algorithm.
			 *
			 * @param persidno The persidno to check, should be of the format "##########"
			 */
			public static bool ValidatePersidno( String persidno ) {

					if( persidno == null ) {
							return false;
					}

					if( persidno.Length != 10 ) {
							return false;
					}

					if( !Regex.IsMatch(persidno, "[0-9]{10}" ) ) {
							return false;
					}

					int sum = int.Parse( persidno[0].ToString() ) * 3;
					sum = sum + int.Parse( persidno[1].ToString() ) * 2;
					sum = sum + int.Parse( persidno[2].ToString() ) * 7;
					sum = sum + int.Parse( persidno[3].ToString() ) * 6;
					sum = sum + int.Parse( persidno[4].ToString() ) * 5;
					sum = sum + int.Parse( persidno[5].ToString() ) * 4;
					sum = sum + int.Parse( persidno[6].ToString() ) * 3;
					sum = sum + int.Parse( persidno[7].ToString() ) * 2;

					int leftovers = (sum % 11);
					int validationNumber = 11 - leftovers;
					int vartala = int.Parse( persidno[8].ToString() );

					if( validationNumber == 11 ) {
							validationNumber = 0;
					}

					if( validationNumber == vartala ) {
							return true;
					}

					return false;
			}

			/**
			 * Attempts to format a persidno string to the standard used in the DB (removes dashes and spaces).
			 *
			 * @param persidno The persidno to format.
			 */
			public static String CleanupPersidno( String persidno ) {

				if( persidno == null ) {
						return null;
				}

				return persidno.Replace("-", "").Replace(" ", "");
			}

			/**
			 * Returns the year that a person was born.
			 */
			public static int BirthyearFromPersidno( String persidno ) {

					if( persidno == null ) {
							return 0;
					}

					string stringPersidno = CleanupPersidno( persidno );

					if( !IsIndividualPersidno( persidno ) ) {
							return 0;
					}

					if( stringPersidno.Length != 10 ) {
							return 0;
					}

					String centuryFull = null;
					String centuryMarker = stringPersidno.Substring( 9, 1 );
					String year = stringPersidno.Substring( 4, 2 );

					if( centuryMarker == "0" ) {
							centuryFull = "20";
					} else {
							centuryFull = "1" + centuryMarker;
					}

					String fullYear = centuryFull + year;

					return int.Parse( fullYear );
			}

			/**
			 * Returns the month that a person was born.
			 */
			public static int BirthMonthFromPersidno( String persidno ) {

					if( persidno == null ) {
							return 0;
					}


					persidno = CleanupPersidno( persidno );

					if( !IsIndividualPersidno( persidno ) ) {
							return 0;
					}

					return int.Parse( persidno.Substring( 2, 2 ) );
			}

			/**
			 * Returns the month that a person was born.
			 */
			public static int BirthDayFromPersidno( String persidno ) {

					if( persidno == null ) {
							return 0;
					}

					persidno = CleanupPersidno( persidno );

					if( !IsIndividualPersidno( persidno ) ) {
							return 0;
					}

					return int.Parse( persidno.Substring( 0, 2 ) );
			}

			/**
			 * Returns a persidno, formatted by inserting a "-" after the birthdate.
			 * returns an empty string if persidno is not valid.
			 *
			 * @param persidno to format
			 * @param delimiter delimiter between the six'th and seven'th decimals
			 * @return formatted persidno
			 */
			public static String FormatPersidno( String persidno ) {
					return FormatPersidno( persidno, DEFAULT_PERSIDNO_DELIMITER );
			}

			/**
			 * Returns a persidno, formatted by inserting the specified delimiter after the birthdate.
			 * returns an empty string if persidno is not valid.
			 *
			 * @param persidno to format
			 * @param delimiter delimiter between the six'th and seven'th decimals
			 * @return formatted persidno
			 */
			public static String FormatPersidno( String persidno, String delimiter ) {

					if( persidno == null ) {
							return "";
					}

					persidno = CleanupPersidno( persidno );

					if( persidno.Length != 10 ) {
							return "";
					}

					return persidno.Substring( 0, 6 ) + delimiter + persidno.Substring( 6 );
			}
	}
}